package com.gxuwz;

import ch.qos.logback.core.db.DBHelper;
import com.gxuwz.bean.Pet;
import com.gxuwz.bean.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.logging.Handler;

/**
 * yuque:https://www.yuque.com/atguigu/springboot/qb7hy2
 * springboot学习笔记:https://blog.csdn.net/u011863024/article/details/113667634
 * https://blog.csdn.net/u011863024/article/details/113667946
 *springboot的依赖管理
 * 1.由springboot的父依赖进行版本管理，如果要修改版本号就配置自己需要的版本，但标签名字要一致
 * 2.我们引入父依赖时不需要指定版本号
 * 3.spring-boot-start-*是官方提供的场景启动器，二*-sprig-boot-start是第三方提供的
 *
 * springboot的自动配置
 * 1.按需配置，都有自己的默认配置
 * 2.包扫描默认是扫描主程序所在的包下的所有组件都会被扫描
 *
 * 自动包扫描规则：主程序所在的包
 * 初始加载自动配置类：
 * 1、利用getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件
 * 2、调用List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)获取到所有需要导入到容器中的配置类
 * 3、利用工厂加载 Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)；得到所有的组件
 * 4、从META-INF/spring.factories位置来加载一个文件。
 *   默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
 *     spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
 *
 *  而springboot2.5.5中：会从缓存中查找不为空时不在执行加载META-INF/spring.factories文件
 *
 *
 *  SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先
 *
 *
 *  总结：
 * ● SpringBoot先加载所有的自动配置类  xxxxxAutoConfiguration
 * ● 每个自动配置类按照条件进行生效，默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
 * ● 生效的配置类就会给容器中装配很多组件
 * ● 只要容器中有这些组件，相当于这些功能就有了
 * ● 定制化配置
 *   ○ 用户直接自己@Bean替换底层的组件
 *   ○ 用户去看这个组件是获取的配置文件什么值就去修改。
 * xxxxxAutoConfiguration ---> 组件  ---> xxxxProperties里面拿值  ----> application.properties
 *
 * 最佳实践:
 * ● 引入场景依赖
 *   ○ https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
 * ● 查看自动配置了哪些（选做）
 *   ○ 自己分析，引入场景对应的自动配置一般都生效了
 *   ○ 配置文件中debug=true开启自动配置报告。Negative（不生效）\Positive（生效）
 * ● 是否需要修改
 *   ○ 参照文档修改配置项
 *     ■ https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties
 *     ■ 自己分析。xxxxProperties绑定了配置文件的哪些。
 *   ○ 自定义加入或者替换组件
 *     ■ @Bean、@Component。。。
 *   ○ 自定义器  XXXXXCustomizer；
 */
@SpringBootApplication
//@RestController
public class Application {

    public static void main(String[] args) {
        //获取所有ioc容器
        ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);

        //获取所有组件的名字
        String[] names = run.getBeanDefinitionNames();

        for (String name:names) {
            System.out.println(name);

        }

        //获取组件,使用注解bean组件创建的组件默认是单实例的
//        User user01 = run.getBean("user01", User.class);
//
//
//        Pet Pet = run.getBean("tom", Pet.class);
//
//        System.out.println(user01.getPet()==Pet);
//
//        //test @Import
//        run.getBeanNamesForType(User.class);
//        DBHelper bean1 = run.getBean(DBHelper.class);
//        System.out.println(bean1);

        //test @ConditionalOnBean
        boolean tom = run.containsBean("tom");
        System.out.println("Tom组件:"+tom);
        boolean user01 = run.containsBean("user01");
        System.out.println("User01组件:"+user01);
        boolean tom22 = run.containsBean("tom22");
        System.out.println("Tom22:"+tom22);

        boolean ha = run.containsBean("ha");
        System.out.println("ha:"+ha);



    }
}
